home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / netmail / rnr214.zip / GENERICF.PAS < prev    next >
Pascal/Delphi Source File  |  1996-02-28  |  44KB  |  2,200 lines

  1. unit genericf;  {generic functions unit - not rnr-specific at all}
  2.  
  3. {
  4.  
  5. Russell_Schulz@locutus.ofB.ORG (960115)
  6.  
  7. Copyright 1996 Russell Schulz
  8.  
  9. this code is not in the Public Domain
  10.  
  11. permission is granted to use these routines in any application regardless
  12. of commercial status as long as the author of these routines assumes no
  13. liability for any damages whatsoever for any reason.  have fun.
  14.  
  15. }
  16.  
  17. {
  18. version of this unit: 1ish
  19. }
  20.  
  21. {$define floatingpoint}
  22. {$undef floatingpoint}
  23.  
  24. interface
  25.  
  26. uses dos;
  27.  
  28. const
  29.   tab=#9;
  30.   esc=#27;
  31.   cr=#13;
  32.   lf=#10;
  33.   space=' ';
  34.   comma=',';
  35.  
  36.   alwayslegalchars: set of char=
  37.   [
  38.    {uppercase letters}
  39.    'A','B','C','D','E','F','G','H','I','J','K','L','M',
  40.    'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
  41.  
  42.    {lowercase letters}
  43.    'a','b','c','d','e','f','g','h','i','j','k','l','m',
  44.    'n','o','p','q','r','s','t','u','v','w','x','y','z',
  45.  
  46.    {digits}
  47.    '0','1','2','3','4','5','6','7','8','9',
  48.  
  49.    {some punctuation}
  50.    '!','#','$','%','&','(',')','-','@','^','_','`','{','}','~',
  51.  
  52.    {and finally, the quote}
  53.    ''''
  54.   ];
  55.  
  56.   sometimeslegalchars: set of char=
  57.   [
  58.    {must be careful with these}
  59.    ':','.','\'
  60.   ];
  61.  
  62.  
  63. function max(a,b: integer): integer;
  64. function min(a,b: integer): integer;
  65. function lmax(a,b: longint): longint;
  66. function lmin(a,b: longint): longint;
  67. function iifs(abool: boolean; truestring, falsestring: string): string;
  68. function leftjustify(s: string; width: integer; c: char): string;
  69. function rightjustify(s: string; width: integer; c: char): string;
  70. function wordtozstring(w: word; width: integer): string;
  71. function integertozstring(i: integer; width: integer): string;
  72. function longtozstring(l: longint; width: integer): string;
  73. function currenttimestring: string;
  74. function currenttimedigits: string;
  75. function dow: integer;
  76. function extcdow(thedow: word): string;
  77. function cdow: string;
  78. function dayofmonth: integer;
  79. function month: integer;
  80. function extmonthname(themonth: integer): string;
  81. function monthname: string;
  82. function year: integer;
  83. function dayofweek(y,m,d: word): word;
  84. function ymdtostring(year, month, day: word): string;
  85. function dateformatted(y,m,d: word; dateformat: string): string;
  86. function timetostring(atime: longint): string;
  87. function currentdatestring: string;
  88. function getenv(s: string): string;
  89. function numoccur(c: char; s: string): integer;
  90. function hasany(c: char; s: string): boolean;
  91. function hasno(c: char; s: string): boolean;
  92. function unquote(s: string): string;
  93. function crepl(s: string; cold, cnew: char): string;
  94. function unslash(s: string): string;
  95. function unbackslash(s: string): string;
  96. function ununderscore(s: string): string;
  97. function uncomma(s: string): string;
  98. function srepl(s: string; sold, snew: string): string;
  99. function srepli(s: string; sold, snew: string): string;
  100. function sreplmulti(s: string; sold, snew: string): string;
  101. function unspace(s: string): string;
  102. function atow(s: string): word;
  103. function atoi(s: string): integer;
  104. function atol(s: string): longint;
  105. function wtoa(w: word): string;
  106. function itoa(i: integer): string;
  107. function ltoa(l: longint): string;
  108. function lowcase(c: char): char;
  109. function upper(s: string): string;
  110. function lower(s: string): string;
  111. function proper(s: string): string;
  112. function ltrim(s: string): string;
  113. function trim(s: string): string;
  114. function right(s: string; i: integer): string;
  115. function getfirstw(s: string): string;
  116. function chopfirstw(var s: string): string;
  117. function getquoted(s: string): string;
  118. function randomletter: char;
  119. function randomdigit: char;
  120. function getfromaddr(from: string): string;
  121. function getfromname(from: string): string;
  122. function lchop(s: string; i: integer): string;
  123. function nore(s: string): string;
  124. function monthstringtointeger(monthstr: string): integer;
  125. function isalpha(c: char): boolean;
  126. function isdigit(c: char): boolean;
  127. function isalnum(c: char): boolean;
  128. function isidentchar(c: char): boolean;
  129. function islower(c: char): boolean;
  130. function isspace(c: char): boolean;
  131. function snatchint(var s: string): integer;
  132. function isdev(s: string): boolean;
  133. function illegalfn(fn: string): boolean;
  134. function suspiciousfn(fn: string): boolean;
  135. function highestartin(groupdir: string): longint;  {used to be word}
  136. function getuniqfile(groupdir: string): string;
  137. function getuniqfext(basename: string): string;
  138. function expand(str: string): string;
  139. function rot13(s: string): string;
  140. function indir(filespec,dir: string): boolean;
  141. function default(defaultstr,possiblyemptystr: string): string;
  142. function rpos(sub: string; whole: string): integer;
  143. function rposc(s: string; c: char): integer;
  144. function fexists(fn: string): boolean;
  145. function dexists(dn: string): boolean;
  146. function getfntime(fn: string): longint;
  147. function getfnsize(fn: string): longint;
  148. function withbackslash(s: string): string;
  149. function nobeep(s: string): string;
  150. function nonastychar(s: string): string;
  151. function gettag(tag: string; s: string): string;
  152. function hexchar(i: integer): char;
  153. function partialmatch(cmd, template, minimum: string): boolean;
  154. function doserrorno: byte;
  155. function wordwith(c:char; s: string): string;
  156. function isasciifile(fn: string): boolean;
  157. function nthfield(astring: string; delim: char; n: integer): string;
  158. function isinlist(astring, alist, delim: string): boolean;
  159. function sornos(n: integer): string;
  160. function regexintext(aregex: string; awholetext: string): boolean;
  161. function enclosedin(astring: string; lchar,rchar: char): boolean;
  162. function isaleapyear(ayear: integer): boolean;
  163. function daysinyear(ayear: integer): integer;
  164. function daysinyearmonth(ayear: integer; amonth: integer): integer;
  165. function dayspast1970(y,m,d: word): longint;
  166.  
  167.  
  168. {$ifdef VER40}
  169. function dosversion: word;
  170. {$endif}
  171.  
  172. {$ifdef floatingpoint}
  173. function ator(s: string): real;
  174. function rtoa(r: real): string;
  175. function rwptoa(r: real; width: integer; precision: integer): string;
  176. function rtonicea(r: real): string;
  177. {$endif}
  178.  
  179. implementation
  180.  
  181. function max;
  182.  
  183. begin
  184.   if a>b then max := a else max := b;
  185. end;
  186.  
  187. function min;
  188.  
  189. begin
  190.   min := -max(-a,-b);
  191. end;
  192.  
  193. function lmax;
  194.  
  195. begin
  196.   if a>b then lmax := a else lmax := b;
  197. end;
  198.  
  199. function lmin;
  200.  
  201. begin
  202.   lmin := -lmax(-a,-b);
  203. end;
  204.  
  205. function iifs;
  206.  
  207. begin
  208.   if abool then
  209.     iifs := truestring
  210.   else
  211.     iifs := falsestring;
  212. end;
  213.  
  214. function leftjustify;
  215.  
  216. var
  217.   result: string;
  218.  
  219. begin
  220.   result := s;
  221.  
  222.   while length(result)<width do
  223.     result := result+c;
  224.  
  225.   leftjustify := result;
  226. end;
  227.  
  228. function rightjustify;
  229.  
  230. var
  231.   result: string;
  232.  
  233. begin
  234.   result := s;
  235.  
  236.   while length(result)<width do
  237.     result := c+result;
  238.  
  239.   rightjustify := result;
  240. end;
  241.  
  242. function wordtozstring;
  243.  
  244. var
  245.   result: string;
  246.  
  247. begin
  248.   str(w,result);
  249.  
  250.   wordtozstring := rightjustify(result,width,'0');
  251. end;
  252.  
  253. function integertozstring;
  254.  
  255. var
  256.   result: string;
  257.  
  258. begin
  259.   str(i,result);
  260.  
  261.   integertozstring := rightjustify(result,width,'0');
  262. end;
  263.  
  264. function longtozstring;
  265.  
  266. var
  267.   result: string;
  268.  
  269. begin
  270.   str(l,result);
  271.  
  272.   longtozstring := rightjustify(result,width,'0');
  273. end;
  274.  
  275. function currenttimestring;
  276.  
  277. var
  278.   h,m,s,s00: word;
  279.  
  280. begin
  281.   gettime(h,m,s,s00);
  282.   currenttimestring :=
  283.    integertozstring(h,2)+':'+integertozstring(m,2)+':'+integertozstring(s,2);
  284. end;
  285.  
  286. function currenttimedigits;
  287.  
  288. var
  289.   h,m,s,s00: word;
  290.  
  291. begin
  292.   gettime(h,m,s,s00);
  293.   currenttimedigits :=
  294.    integertozstring(h,2)+integertozstring(m,2)+integertozstring(s,2);
  295. end;
  296.  
  297. function dow;
  298.  
  299. var
  300.   y,m,d,realdow: word;
  301.  
  302. begin
  303.   getdate(y,m,d,realdow);
  304.   dow := realdow;
  305. end;
  306.  
  307. function extcdow;
  308.  
  309. var
  310.   result: string;
  311.  
  312. begin
  313.   result := 'Sunday';
  314.   if thedow=1 then result := 'Monday';
  315.   if thedow=2 then result := 'Tuesday';
  316.   if thedow=3 then result := 'Wednesday';
  317.   if thedow=4 then result := 'Thursday';
  318.   if thedow=5 then result := 'Friday';
  319.   if thedow=6 then result := 'Saturday';
  320.  
  321.   extcdow := result;
  322. end;
  323.  
  324. function cdow;
  325.  
  326. begin
  327.   cdow := extcdow(dow);
  328. end;
  329.  
  330. function dayofmonth;
  331.  
  332. var
  333.   y,m,d,dow: word;
  334.  
  335. begin
  336.   getdate(y,m,d,dow);
  337.   dayofmonth := d;
  338. end;
  339.  
  340. function month;
  341.  
  342. var
  343.   y,m,d,dow: word;
  344.  
  345. begin
  346.   getdate(y,m,d,dow);
  347.   month := m;
  348. end;
  349.  
  350. function extmonthname;
  351.  
  352. var
  353.   result: string;
  354.  
  355. begin
  356.   result := 'January';
  357.   if themonth=2  then result := 'February';
  358.   if themonth=3  then result := 'March';
  359.   if themonth=4  then result := 'April';
  360.   if themonth=5  then result := 'May';
  361.   if themonth=6  then result := 'June';
  362.   if themonth=7  then result := 'July';
  363.   if themonth=8  then result := 'August';
  364.   if themonth=9  then result := 'September';
  365.   if themonth=10 then result := 'October';
  366.   if themonth=11 then result := 'November';
  367.   if themonth=12 then result := 'December';
  368.  
  369.   extmonthname := result;
  370. end;
  371.  
  372. function monthname;
  373.  
  374. begin
  375.   monthname := extmonthname(month);
  376. end;
  377.  
  378. function year;
  379.  
  380. var
  381.   y,m,d,dow: word;
  382.  
  383. begin
  384.   getdate(y,m,d,dow);
  385.   year := y;
  386. end;
  387.  
  388. function dayofweek;
  389.  
  390. var
  391.   result: word;
  392.  
  393.   century: word;
  394.   year: word;
  395.   month: word;
  396.  
  397. begin
  398. {
  399.  
  400. from an old sci.math FAQ
  401.  
  402. 15Q:  Is there a formula to determine the day of the week, given
  403.     the month, day and year? 
  404.  
  405. A:  Here is the standard method.
  406.  
  407. [...]
  408.  
  409.     Another formula is:
  410.  
  411.     W == k + [2.6m - 0.2] - 2C + Y + [Y/4] + [C/4]     mod 7
  412.        where [] denotes the integer floor function (round down),
  413.        k is day (1 to 31)
  414.        m is month (1 = March, ..., 10 = December, 11 = Jan, 12 = Feb)
  415.                      Treat Jan & Feb as months of the preceding year
  416.        C is century ( 1987 has C = 19)
  417.        Y is year    ( 1987 has Y = 87 except Y = 86 for jan & feb)
  418.        W is week day (0 = Sunday, ..., 6 = Saturday)
  419.  
  420.     This formula is good for the Gregorian calendar
  421.     (introduced 1582 in parts of Europe, adopted in 1752 in Great Britain
  422.     and its colonies, and on various dates in other countries).
  423.  
  424.     It handles century & 400 year corrections, but there is still a 
  425.     3 day / 10,000 year error which the Gregorian calendar does not take.
  426.     into account.  At some time such a correction will have to be 
  427.     done but your software will probably not last that long :-)   !
  428.  
  429.  
  430.     References:
  431.  
  432.     Winning Ways  by Conway, Guy, Berlekamp is supposed to have it.
  433.  
  434.     Martin Gardner in "Mathematical Carnival".
  435.  
  436.     Michael Keith and Tom Craver, "The Ultimate Perpetual Calendar?",
  437.     Journal of Recreational Mathematics, 22:4, pp. 280-282, 1990.
  438.     
  439.     K. Rosen, "Elementary Number Theory",  p. 156.
  440.  
  441. }
  442.  
  443.   year := y;
  444.   month := m;
  445.  
  446.   if month<3 then
  447.     begin
  448.       inc(month,12);
  449.       dec(year);
  450.     end;
  451.  
  452.   dec(month,2);
  453.  
  454.   century := (year div 100);
  455.   year := year mod 100;
  456.  
  457.   result := d+trunc(2.6*month-0.2)-2*century+year+year div 4+century div 4;
  458.  
  459. {handle negative mods}
  460.   result := result mod 7;
  461.   if result<0 then
  462.     result := 7+result;
  463.  
  464.   dayofweek := result;
  465. end;
  466.  
  467. function ymdtostring;
  468.  
  469. begin
  470.   ymdtostring := wordtozstring(year,2)+'-'+
  471.    wordtozstring(month,2)+'-'+wordtozstring(day,2);
  472. end;
  473.  
  474. function timetostring;
  475.  
  476. var
  477.   result: string;
  478.   dt: datetime;
  479.  
  480. begin
  481.   unpacktime(atime,dt);
  482.   result :=
  483.        wordtozstring(dt.year,4)+
  484.    '/'+wordtozstring(dt.month,2)+
  485.    '/'+wordtozstring(dt.day,2)+
  486.    '_'+wordtozstring(dt.hour,2)+
  487.    ':'+wordtozstring(dt.min,2)+
  488.    ':'+wordtozstring(dt.sec,2);
  489.   timetostring := result;
  490. end;
  491.  
  492. function dateformatted;
  493.  
  494. const
  495.   wstrings='SMTWRFA';
  496.  
  497. var
  498.   result: string;
  499.   tempformat: string;
  500.   formatchars: integer;
  501.   dow: integer;
  502.  
  503. begin
  504.   result := '';
  505.   dow := -1; {unknown}
  506.  
  507.   if (dateformat<>'') and (dateformat<>'-') then
  508.     begin
  509.       tempformat := dateformat;
  510.       while tempformat<>'' do
  511.         begin
  512.           if copy(tempformat,1,1)='s' then
  513.             begin
  514.               result := result+' ';
  515.               formatchars := 1;
  516.             end
  517.           else if copy(tempformat,1,3)='www' then
  518.             begin
  519.               if dow<0 then
  520.                 dow := dayofweek(y,m,d);
  521.               result := result+copy(extcdow(dow),1,3);
  522.               formatchars := 3;
  523.             end
  524.           else if copy(tempformat,1,2)='ww' then
  525.             begin
  526.               if dow<0 then
  527.                 dow := dayofweek(y,m,d);
  528.               result := result+copy(extcdow(dow),1,2);
  529.               formatchars := 2;
  530.             end
  531.           else if copy(tempformat,1,1)='w' then
  532.             begin
  533.               if dow<0 then
  534.                 dow := dayofweek(y,m,d);
  535.               result := result+copy(wstrings,1+dow,1);
  536.               formatchars := 1;
  537.             end
  538.           else if copy(tempformat,1,4)='yyyy' then
  539.             begin
  540.               result := result+wordtozstring(y,4);
  541.               formatchars := 4;
  542.             end
  543.           else if copy(tempformat,1,2)='yy' then
  544.             begin
  545.               result := result+wordtozstring(y mod 100,2);
  546.               formatchars := 2;
  547.             end
  548.           else if copy(tempformat,1,3)='mmm' then
  549.             begin
  550.               result := result+copy(extmonthname(m),1,3);
  551.               formatchars := 3;
  552.             end
  553.           else if copy(tempformat,1,2)='mm' then
  554.             begin
  555.               result := result+wordtozstring(m,2);
  556.               formatchars := 2;
  557.             end
  558.           else if copy(tempformat,1,2)='dd' then
  559.             begin
  560.               result := result+wordtozstring(d,2);
  561.               formatchars := 2;
  562.             end
  563.           else
  564.             begin
  565.               result := result+copy(tempformat,1,1);
  566.               formatchars := 1;
  567.             end;
  568.  
  569.           tempformat := lchop(tempformat,formatchars);
  570.         end;
  571.     end;
  572.  
  573.   dateformatted := result;
  574. end;
  575.  
  576. function currentdatestring;
  577.  
  578. var
  579.   year, month, day, dayofweek: word;
  580.  
  581. begin
  582.   getdate(year,month,day,dayofweek);
  583.   currentdatestring := ymdtostring(year,month,day);
  584. end;
  585.  
  586. function getenv;
  587.  
  588. var
  589.   result: string;
  590.  
  591.   i: integer;
  592.   envseg: word;
  593.   envread: integer;
  594.   firstb: byte;
  595.   thisb: byte;
  596.   varname: string;
  597.   vardata: string;
  598.   done: boolean;
  599.  
  600. begin
  601.   result := '';
  602.  
  603.   envseg := memw[prefixseg:$2c];
  604.  
  605.   envread := 0;
  606.   repeat
  607.     firstb := mem[envseg:envread];
  608.  
  609.     if firstb>0 then
  610.       begin
  611.         varname := '';
  612.  
  613.         repeat
  614.           thisb := mem[envseg:envread];
  615.           inc(envread);
  616.           if thisb<>ord('=') then
  617.             varname := varname+chr(thisb);
  618.         until thisb=ord('=');
  619.  
  620.         vardata := '';
  621.  
  622.         repeat
  623.           thisb := mem[envseg:envread];
  624.           inc(envread);
  625.           if thisb>0 then
  626.             vardata := vardata+chr(thisb);
  627.         until thisb=0;
  628.  
  629.         done := (varname=s);
  630.         if done then
  631.           result := vardata;
  632.     end;
  633.   until (firstb=0) or done;
  634.  
  635.   getenv := result;
  636. end;
  637.  
  638. function numoccur;
  639.  
  640. var
  641.   result: integer;
  642.   i: integer;
  643.  
  644. begin
  645.   result := 0;
  646.  
  647.   for i := 1 to length(s) do
  648.     if s[i]=c then
  649.       inc(result);
  650.  
  651.   numoccur := result;
  652. end;
  653.  
  654. function hasany;
  655.  
  656. begin
  657.   hasany := (numoccur(c,s)<>0);
  658. end;
  659.  
  660. function hasno;
  661.  
  662. begin
  663.   hasno := not hasany(c,s);
  664. end;
  665.  
  666. function unquote;
  667.  
  668. begin
  669.   if (s[1]='"') and (s[length(s)]='"') then
  670.     unquote := copy(s,2,length(s)-2)
  671.   else
  672.     unquote := s;
  673. end;
  674.  
  675. function crepl;
  676.  
  677. var
  678.   result: string;
  679.   i: integer;
  680.  
  681. begin
  682.   result := s;
  683.  
  684.   for i := 1 to length(result) do
  685.     if result[i]=cold then
  686.       result[i] := cnew;
  687.  
  688.   crepl := result;
  689. end;
  690.  
  691. function unslash;
  692.  
  693. begin
  694.   unslash := crepl(s,'/','\');
  695. end;
  696.  
  697. function unbackslash;
  698.  
  699. begin
  700.   if s='' then
  701.     unbackslash := s
  702.   else if copy(s,length(s),1)='\' then
  703.     unbackslash := copy(s,1,length(s)-1)
  704.   else
  705.     unbackslash := s;
  706. end;
  707.  
  708. function ununderscore;
  709.  
  710. begin
  711.   ununderscore := crepl(s,'_',space);
  712. end;
  713.  
  714. function uncomma;
  715.  
  716. begin
  717.   uncomma := crepl(s,comma,space);
  718. end;
  719.  
  720. {}{}{}{} { srepl('aa','a','') doesn't work :-( }
  721.  
  722. function srepl;
  723.  
  724. var
  725.   result: string;
  726.   at: integer;
  727.  
  728. begin
  729.   result := s;
  730.  
  731.   if (sold<>'') and (sold<>snew) then
  732.     begin
  733.       at := 0;
  734.       while at<=length(result)-length(sold) do
  735.         begin
  736.           inc(at);
  737.           if result[at]=sold[1] then
  738.             if copy(result,at,length(sold))=sold then
  739.               begin
  740.                 if sold=result then
  741.                   result := snew
  742.                 else if at=1 then
  743.                   result := snew+copy(result,length(sold)+1,255)
  744.                 else if at=length(result)-length(sold)+1 then
  745.                   result := copy(result,1,at-1)+snew
  746.                 else
  747.                   result :=
  748.                    copy(result,1,at-1)+snew+copy(result,at+length(sold),255);
  749.             end;
  750.         end;
  751.     end;
  752.  
  753.   srepl := result;
  754. end;
  755.  
  756. function srepli; {case-insensitive}
  757.  
  758. var
  759.   result: string;
  760.   at: integer;
  761.   uppersold: string;
  762.  
  763. begin
  764.   result := s;
  765.   uppersold := upper(sold);
  766.  
  767.   if (sold<>'') and (uppersold<>upper(snew)) then
  768.     begin
  769.       at := 0;
  770.       while at<=length(result)-length(sold) do
  771.         begin
  772.           inc(at);
  773.           if upcase(result[at])=uppersold[1] then
  774.             if upper(copy(result,at,length(sold)))=uppersold then
  775.               begin
  776.                 if uppersold=upper(result) then
  777.                   result := snew
  778.                 else if at=1 then
  779.                   result := snew+copy(result,length(sold)+1,255)
  780.                 else if at=length(result)-length(sold)+1 then
  781.                   result := copy(result,1,at-1)+snew
  782.                 else
  783.                   result :=
  784.                    copy(result,1,at-1)+snew+copy(result,at+length(sold),255);
  785.             end;
  786.         end;
  787.     end;
  788.  
  789.   srepli := result;
  790. end;
  791.  
  792. function sreplmulti;
  793.  
  794. var
  795.   result: string;
  796.   firstpass: string;
  797.  
  798. begin
  799.   firstpass := srepl(s,sold,snew);
  800.   result := firstpass;
  801.  
  802.   if firstpass<>s then
  803.     result := srepl(firstpass,sold,snew);
  804.  
  805.   if result<>firstpass then
  806.     result := srepl(result,sold,snew);
  807.  
  808.   sreplmulti := result;
  809. end;
  810.  
  811. function unspace;
  812.  
  813. var
  814.   result: string;
  815.   i: integer;
  816.  
  817. begin
  818.   if (numoccur(' ',s)=0) and (numoccur(tab,s)=0) then
  819.     result := s
  820.   else
  821.     begin
  822.       result := '';
  823.       for i := 1 to length(s) do
  824.         if (s[i]<>' ') and (s[i]<>tab) then
  825.           result := result+s[i];
  826.     end;
  827.  
  828.   unspace := result;
  829. end;
  830.  
  831. function atow;
  832.  
  833. var
  834.   result: word;
  835.   code: word;
  836.  
  837. begin
  838.   val(s,result,code);
  839.   atow := result;
  840. end;
  841.  
  842. function atoi;
  843.  
  844. var
  845.   result: integer;
  846.   code: word;
  847.  
  848. begin
  849.   val(s,result,code);
  850.   atoi := result;
  851. end;
  852.  
  853. function atol;
  854.  
  855. var
  856.   result: longint;
  857.   code: word;
  858.  
  859. begin
  860.   val(s,result,code);
  861.   atol := result;
  862. end;
  863.  
  864. function wtoa;
  865.  
  866. begin
  867.   wtoa := wordtozstring(w,0);
  868. end;
  869.  
  870. function itoa;
  871.  
  872. begin
  873.   itoa := integertozstring(i,0);
  874. end;
  875.  
  876. function ltoa;
  877.  
  878. begin
  879.   ltoa := longtozstring(l,0);
  880. end;
  881.  
  882. function lowcase; {similar to the supplied upcase}
  883.  
  884. begin
  885.   if (c>='A') and (c<='Z') then
  886.     lowcase := chr(ord(c)-ord('A')+ord('a'))
  887.   else
  888.     lowcase := c;
  889. end;
  890.  
  891. function upper;
  892.  
  893. var
  894.   result: string;
  895.   i: integer;
  896.  
  897. begin
  898.   result := s;
  899.  
  900.   for i := 1 to length(s) do
  901.     result[i] := upcase(result[i]);
  902.  
  903.   upper := result;
  904. end;
  905.  
  906. function lower;
  907.  
  908. var
  909.   result: string;
  910.   i: integer;
  911.  
  912. begin
  913.   result := s;
  914.  
  915.   for i := 1 to length(s) do
  916.     result[i] := lowcase(result[i]);
  917.  
  918.   lower := result;
  919. end;
  920.  
  921. function proper;
  922.  
  923. var
  924.   result: string;
  925.   i: integer;
  926.   shouldup: boolean;
  927.  
  928. begin
  929.   result := s;
  930.  
  931.   shouldup := true;
  932.  
  933.   for i := 1 to length(s) do
  934.     begin
  935.       if shouldup then
  936.         result[i] := upcase(result[i])
  937.       else
  938.         result[i] := lowcase(result[i]);
  939.       shouldup := not isalpha(result[i]);
  940.     end;
  941.  
  942.   proper := result;
  943. end;
  944.  
  945. function ltrim;
  946.  
  947. var
  948.   result: string;
  949.  
  950. begin
  951.   result := s;
  952.  
  953.   while ((result[1]=' ') or (result[1]=tab)) and (length(result)>0) do
  954.     result := copy(result,2,255);
  955.  
  956.   ltrim := result;
  957. end;
  958.  
  959. function trim;
  960.  
  961. var
  962.   result: string;
  963.  
  964. begin
  965.   result := s;
  966.  
  967.   while ((result[length(result)]=' ') or (result[length(result)]=tab)) and
  968.    (length(result)>0) do
  969.     result := copy(result,1,length(result)-1);
  970.  
  971.   trim := result;
  972. end;
  973.  
  974. function right;
  975.  
  976. begin
  977.   right := copy(s,max(1,length(s)-i+1),i);
  978. end;
  979.  
  980. function getfirstw;
  981.  
  982. var
  983.   result: string;
  984.   spaceat: integer;
  985.   tabat: integer;
  986.  
  987. begin
  988.   result := trim(ltrim(s));
  989.   spaceat := pos(' ',result);
  990.   tabat := pos(tab,result);
  991.  
  992.   if tabat>0 then
  993.     if (spaceat>0) and (tabat>spaceat) then
  994.       result := copy(result,1,spaceat-1)
  995.     else
  996.       result := copy(result,1,tabat-1)
  997.   else
  998.     if spaceat>0 then
  999.       result := copy(result,1,spaceat-1);
  1000.  
  1001.   getfirstw := result;
  1002. end;
  1003.  
  1004. function chopfirstw;
  1005.  
  1006. var
  1007.   result: string;
  1008.  
  1009. begin
  1010.   s := trim(ltrim(s));
  1011.   result := getfirstw(s);
  1012.   s := ltrim(copy(s,length(result)+1,255));
  1013.  
  1014.   chopfirstw := result;
  1015. end;
  1016.  
  1017. function getquoted;
  1018.  
  1019. var
  1020.   result: string;
  1021.  
  1022. begin
  1023.   result := '';
  1024.  
  1025.   if copy(s,1,1)='"' then
  1026.     begin
  1027.       result := copy(s,2,255);
  1028.       if pos('"',result)=0 then
  1029.         result := getfirstw(result)
  1030.       else
  1031.         result := copy(result,1,pos('"',result)-1);
  1032.     end
  1033.   else
  1034.     result := getfirstw(s);
  1035.  
  1036.   getquoted := result;
  1037. end;
  1038.  
  1039. function randomletter;
  1040.  
  1041. begin
  1042.   if random(2)=0 then
  1043.     randomletter := chr(ord('a')+random(26))
  1044.   else
  1045.     randomletter := chr(ord('A')+random(26));
  1046. end;
  1047.  
  1048. function randomdigit;
  1049.  
  1050. begin
  1051.   randomdigit := chr(ord('0')+random(10));
  1052. end;
  1053.  
  1054. function getfromaddr;
  1055.  
  1056. var
  1057.   result: string;
  1058.   at: integer;
  1059.  
  1060. begin
  1061.   at := rpos('<',from);  {used to be pos, but that didn't work on illegals}
  1062.  
  1063.   if at>0 then {Full Name <address>}
  1064.     result := copy(from,at+1,length(from)-at-1)
  1065.   else
  1066.     begin
  1067.       at := pos(' ',from);
  1068.       if at>0 then {address (Full Name)}
  1069.         result := copy(from,1,at-1)
  1070.       else {address}
  1071.         result := from;
  1072.     end;
  1073.  
  1074.   getfromaddr := result;
  1075. end;
  1076.  
  1077. {be careful with address like
  1078.  
  1079.   "Some (Happy) User" <some@happy.com>
  1080.  
  1081. - need to grab the right parts right}
  1082.  
  1083. function getfromname;
  1084.  
  1085. var
  1086.   result: string;
  1087.   at: integer;
  1088.  
  1089. begin
  1090.   result := '';
  1091.  
  1092.   if copy(from,length(from),1)='>' then
  1093.     begin
  1094.       at := rpos('<',from);  {not pos to avoid breaking illegal headers}
  1095.       if at>1 then
  1096.         result := copy(from,1,at-2);
  1097.     end;
  1098.  
  1099.   if result='' then
  1100.     begin
  1101.       at := pos('(',from);
  1102.       if at>0 then
  1103.         result := copy(from,at+1,length(from)-at-1)
  1104.       else
  1105.         begin
  1106.           at := rpos('<',from);
  1107.           if at>1 then
  1108.             result := copy(from,1,at-2);
  1109.         end;
  1110.     end;
  1111.  
  1112.   getfromname := unquote(result);
  1113. end;
  1114.  
  1115. {changed from `chop' to `lchop' since perl's chop chops from the right}
  1116. function lchop;
  1117.  
  1118. var
  1119.   result: string;
  1120.  
  1121. begin
  1122.   lchop := copy(s,i+1,255);
  1123. end;
  1124.  
  1125. function nore;
  1126.  
  1127. begin
  1128.  
  1129. {should always be 4 and 'Re: ', but uppercase and ltrim to deal with others}
  1130.  
  1131.   if upper(copy(s,1,3))='RE:' then
  1132.     nore := ltrim(lchop(s,3))
  1133.   else
  1134.     nore := s;
  1135. end;
  1136.  
  1137. function monthstringtointeger;
  1138.  
  1139. var
  1140.   result: integer;
  1141.   lowermonthstr: string;
  1142.  
  1143. begin
  1144.   result := 12;
  1145.  
  1146.   lowermonthstr := lower(monthstr);
  1147.  
  1148.   if lowermonthstr='jan' then result := 1
  1149.   else if lowermonthstr='feb' then result := 2
  1150.   else if lowermonthstr='mar' then result := 3
  1151.   else if lowermonthstr='apr' then result := 4
  1152.   else if lowermonthstr='may' then result := 5
  1153.   else if lowermonthstr='jun' then result := 6
  1154.   else if lowermonthstr='jul' then result := 7
  1155.   else if lowermonthstr='aug' then result := 8
  1156.   else if lowermonthstr='sep' then result := 9
  1157.   else if lowermonthstr='oct' then result := 10
  1158.   else if lowermonthstr='nov' then result := 11;
  1159.  
  1160.   monthstringtointeger := result;
  1161. end;
  1162.  
  1163. function isalpha;
  1164.  
  1165. begin
  1166.   isalpha := ( (upcase(c)>='A') and (upcase(c)<='Z') );
  1167. end;
  1168.  
  1169. function isdigit;
  1170.  
  1171. begin
  1172.   isdigit := (c>='0') and (c<='9');
  1173. end;
  1174.  
  1175. function isalnum;
  1176.  
  1177. begin
  1178.   isalnum := isalpha(c) or isdigit(c);
  1179. end;
  1180.  
  1181. function isidentchar;
  1182.  
  1183. begin
  1184.   isidentchar := isalpha(c) or isdigit(c) or (c='_');
  1185. end;
  1186.  
  1187. function islower;
  1188.  
  1189. begin
  1190.   islower := (c>='a') and (c<='z');
  1191. end;
  1192.  
  1193. function isspace;
  1194.  
  1195. begin
  1196.   isspace := (c=' ') or (c=tab) or (c=cr) or (c=lf);
  1197. end;
  1198.  
  1199. function snatchint;
  1200.  
  1201. var
  1202.   intsofar: integer;
  1203.  
  1204. begin
  1205.   intsofar := 0;
  1206.  
  1207.   while (length(s)>0) and not isdigit(s[1]) do
  1208.     s := lchop(s,1);
  1209.  
  1210.   while (length(s)>0) and isdigit(s[1]) do
  1211.     begin
  1212.       intsofar := 10*intsofar+ord(s[1])-ord('0');
  1213.       s := lchop(s,1);
  1214.     end;
  1215.  
  1216.   snatchint := intsofar;
  1217. end;
  1218.  
  1219. function isdev;
  1220.  
  1221. {isdev is not perfect -- it always stops on the 128th iteration, just in case}
  1222.  
  1223. var
  1224.   result: boolean;
  1225.   offs: word;
  1226.   segm: word;
  1227.   oldsegm: word;
  1228.   foundnul: boolean;
  1229.   basename: string;
  1230.   i: integer;
  1231.   iterations: integer;
  1232.  
  1233. begin
  1234.   result := false;
  1235.  
  1236.   iterations := 0;
  1237.  
  1238.   segm := 0;
  1239.   offs := $400;
  1240.  
  1241.   basename := upper(unslash(s));
  1242.  
  1243. {handle LPT1: case}
  1244.   if copy(basename,length(basename),1)=':' then
  1245.     basename := copy(basename,1,length(basename)-1);
  1246.  
  1247. {strip disk and path designators}
  1248.   while pos(':',basename)<>0 do
  1249.     basename := copy(basename,pos(':',basename)+1,255);
  1250.   while pos('\',basename)<>0 do
  1251.     basename := copy(basename,pos('\',basename)+1,255);
  1252.  
  1253. {strip anything after the first period}
  1254.   if pos('.',basename)<>0 then
  1255.     basename := copy(basename,1,pos('.',basename)-1);
  1256.  
  1257. {NUL is supposed to be guaranteed the first in the chain}
  1258.   foundnul := false;
  1259.   while (not foundnul) and (offs>0) do
  1260.     begin
  1261.  
  1262. {offs is always in range 1..400 here}
  1263.  
  1264.       if (mem[segm:offs]=ord('N')) and
  1265.        (mem[segm:offs+1]=ord('U')) and
  1266.        (mem[segm:offs+2]=ord('L')) and
  1267.        (mem[segm:offs+3]=ord(' ')) and
  1268.        (mem[segm:offs+4]=ord(' ')) and
  1269.        (mem[segm:offs+5]=ord(' ')) and
  1270.        (mem[segm:offs+6]=ord(' ')) and
  1271.        (mem[segm:offs+7]=ord(' ')) then
  1272.         begin
  1273.  
  1274.           if offs<6 then
  1275.             begin
  1276.               writeln('!! error in isdev: offs<6, first loop -- see source');
  1277.               halt(1);
  1278.             end;
  1279.  
  1280. {$ifdef devverbose}
  1281.           writeln('found NUL at ',offs);
  1282.           writeln('attrib=',memw[segm:offs-6]);
  1283. {$endif}
  1284.  
  1285.           if memw[segm:offs-6]=$8004 then
  1286.             begin
  1287.  
  1288. {$ifdef devverbose}
  1289.               writeln('looks like the real NUL to me!');
  1290. {$endif}
  1291.  
  1292.               foundnul := true;
  1293.             end;
  1294.         end;
  1295.  
  1296.       if not foundnul then
  1297.         inc(offs);
  1298.     end;
  1299.  
  1300.   if foundnul then
  1301.     begin
  1302.  
  1303.       while length(basename)<8 do
  1304.         basename := basename+' ';
  1305.  
  1306.       if offs<10 then
  1307.         begin
  1308.           inc(offs,32);
  1309.           dec(segm,2);
  1310.         end;
  1311.  
  1312.       if offs>65000 then
  1313.         begin
  1314.           dec(offs,32);
  1315.           inc(segm,2);
  1316.         end;
  1317.  
  1318.       while not result and
  1319.        (meml[segm:offs-10]<>$ffffffff) and
  1320.        (iterations<128) do
  1321.  
  1322.         begin
  1323.           inc(iterations);
  1324.  
  1325.           result := true;
  1326.           for i := 0 to 7 do
  1327.             result := result and (chr(mem[segm:offs+i])=basename[1+i]);
  1328.  
  1329. {$ifdef devverbose}
  1330.           writeln('name of device=',
  1331.            chr(mem[segm:offs]),
  1332.            chr(mem[segm:offs+1]),
  1333.            chr(mem[segm:offs+2]),
  1334.            chr(mem[segm:offs+3]),
  1335.            chr(mem[segm:offs+4]),
  1336.            chr(mem[segm:offs+5]),
  1337.            chr(mem[segm:offs+6]),
  1338.            chr(mem[segm:offs+7]),
  1339.            '.');
  1340.  
  1341.           writeln('new position: ',memw[segm:offs-10],':',memw[segm:offs-8]);
  1342. {$endif}
  1343.  
  1344.           oldsegm := segm;
  1345.           segm := memw[oldsegm:offs-8];
  1346.           offs := memw[oldsegm:offs-10];
  1347.  
  1348.           if offs<10 then
  1349.             begin
  1350.               inc(offs,32);
  1351.               dec(segm,2);
  1352.             end;
  1353.  
  1354.           if offs>65000 then
  1355.             begin
  1356.               dec(offs,32);
  1357.               inc(segm,2);
  1358.             end;
  1359.  
  1360.           offs := offs+10;
  1361.  
  1362.         end;
  1363.  
  1364.     end;
  1365.  
  1366.   if iterations>=128 then
  1367.     writeln(
  1368.      '(don''t worry!) isdev could not check for a device,',
  1369.      ' continuing anyway');
  1370.  
  1371.   isdev := result;
  1372. end;
  1373.  
  1374. {$ifdef testfn}
  1375. program testfn;  {tests what characters are legal in filenames}
  1376.  
  1377. var
  1378.   i: integer;
  1379.   fn: string;
  1380.   f: text;
  1381.  
  1382. begin
  1383.   for i := 1 to 255 do
  1384.     begin
  1385.       fn := '';
  1386.       fn := fn+chr(((i        ) div 100)+ord('0'));
  1387.       fn := fn+chr(((i mod 100) div  10)+ord('0'));
  1388.       fn := fn+chr(((i mod  10)        )+ord('0'));
  1389.       fn := fn+'_';
  1390.       fn := fn+chr(i);
  1391.       assign(f,fn);
  1392. {$I-}
  1393.       rewrite(f);
  1394. {$I+}
  1395.       if ioresult=0 then
  1396.         close(f);
  1397.  
  1398.       writeln(i);
  1399.     end;
  1400. end.
  1401. {$endif}
  1402.  
  1403. function illegalfn;  {only works on unslash()ed strings}
  1404.  
  1405. var
  1406.   result: boolean;
  1407.   i: integer;
  1408.   components: string;
  1409.   acomponent: string;
  1410.  
  1411. begin
  1412.  
  1413. {if colon, must be col 2 -- don't use things like lpt1: or com1: }
  1414.  
  1415.   result := false;
  1416.  
  1417.   if numoccur(':',fn)>1 then              { can't have two colons }
  1418.     result := true
  1419.   else if (pos(':',fn)<>0) and (pos(':',fn)<>2) then
  1420.     result := true;
  1421.  
  1422.   for i := 1 to length(fn) do
  1423.     if not result then
  1424.       if not (fn[i] in alwayslegalchars) then
  1425.         if not (fn[i] in sometimeslegalchars) then
  1426.           result := true;
  1427.  
  1428.   if not result then
  1429.     begin
  1430.       components := fn;
  1431.       if pos(':',components)<>0 then
  1432.         components := copy(components,pos(':',components)+1,255);
  1433.  
  1434.       components := trim(ltrim(crepl(components,'\',' ')));
  1435.       while components<>'' do
  1436.         begin
  1437.           acomponent := chopfirstw(components);
  1438.           for i := 1 to length(acomponent) do
  1439.             if numoccur('.',acomponent)>1 then
  1440.               result := true
  1441.             else if acomponent[1]='.' then
  1442.               result := true;
  1443.         end;
  1444.     end;
  1445.  
  1446.   illegalfn := result;
  1447. end;
  1448.  
  1449. function suspiciousfn;
  1450.  
  1451. {note that unslash must have already been used!}
  1452.  
  1453. var
  1454.   result: boolean;
  1455.   upfn: string;
  1456.  
  1457. begin
  1458.   result := false;
  1459.   upfn := upper(fn);
  1460.  
  1461.   if illegalfn(upfn) then
  1462.     result := true
  1463.   else if numoccur(':',upfn)>0 then
  1464.     result := true
  1465.   else if numoccur('\',upfn)>0 then
  1466.     result := true
  1467.   else {common devices just in case isdev misses them}
  1468.     if (upfn='CON') or
  1469.      (upfn='PRN') or
  1470.      (upfn='AUX') or
  1471.      (upfn='NUL') or
  1472.      (upfn='LPT1') or
  1473.      (upfn='LPT2') or
  1474.      (upfn='LPT3') or
  1475.      (upfn='COM1') or
  1476.      (upfn='COM2') or
  1477.      (upfn='COM3') or
  1478.      (upfn='COM4') or
  1479.      (upfn='CLOCK$') then
  1480.       result := true
  1481.   else {isdev uses icky memory peeking, so don't run it if you can avoid it}
  1482.     if isdev(upfn) then
  1483.       result := true;
  1484.  
  1485.   suspiciousfn := result;
  1486. end;
  1487.  
  1488. function highestartin;
  1489.  
  1490. var
  1491.   result: longint;
  1492.   fileinfo: searchrec;
  1493.  
  1494. begin
  1495.   result := 0;
  1496.  
  1497.   findfirst(withbackslash(groupdir)+'*',archive,fileinfo);
  1498.   while doserror=0 do
  1499.     begin
  1500.       result := lmax(result,atol(fileinfo.name));
  1501.       findnext(fileinfo);
  1502.     end;
  1503.  
  1504.   highestartin := result;
  1505. end;
  1506.  
  1507. function getuniqfile;
  1508.  
  1509. var
  1510.   result: string;
  1511.   mangledgroupdir: string;
  1512.  
  1513. begin
  1514.   mangledgroupdir := groupdir;
  1515.  
  1516. {}{need to keep each directory under 8 chars}
  1517.  
  1518. {avoid problems when keeping outbox copy for mail to foo@prn.com etc.}
  1519.  
  1520.   if isdev(mangledgroupdir) then
  1521.     begin
  1522.       mangledgroupdir := groupdir+'_';
  1523.  
  1524. {some device names are 8 chars, and just adding a `_' won't help}
  1525.  
  1526.       if isdev(mangledgroupdir) then
  1527.         mangledgroupdir := copy(groupdir,1,length(groupdir)-1)+'_';
  1528.     end;
  1529.  
  1530.   getuniqfile := withbackslash(mangledgroupdir)+
  1531.    ltoa(highestartin(mangledgroupdir)+1);
  1532. end;
  1533.  
  1534. function getuniqfext;
  1535.  
  1536. var
  1537.   result: word;
  1538.   fileinfo: searchrec;
  1539.   filefound: string;
  1540.   mangledbasename: string;
  1541.  
  1542. begin
  1543.   result := 0;
  1544.   mangledbasename := basename;
  1545.  
  1546. {}{need to keep each directory under 8 chars}
  1547.  
  1548. {avoid problems when keeping outbox copy for mail to foo@prn.com etc.}
  1549.  
  1550.   if isdev(mangledbasename) then
  1551.     begin
  1552.       mangledbasename := basename+'_';
  1553.  
  1554. {some device names are 8 chars, and just adding a `_' won't help}
  1555.  
  1556.       if isdev(mangledbasename) then
  1557.         mangledbasename := copy(basename,1,length(basename)-1)+'_';
  1558.     end;
  1559.  
  1560.   findfirst(mangledbasename+'.*',archive,fileinfo);
  1561.   while doserror=0 do
  1562.     begin
  1563.       filefound := fileinfo.name;
  1564.       while pos('.',filefound)>0 do
  1565.         filefound := copy(filefound,pos('.',filefound)+1,255);
  1566.       result := max(result,atoi(filefound));
  1567.       findnext(fileinfo);
  1568.     end;
  1569.  
  1570.   getuniqfext := mangledbasename+'.'+wtoa(result+1);
  1571. end;
  1572.  
  1573. function expand;
  1574.  
  1575. var
  1576.   work: string;
  1577.   i,j: integer;
  1578.  
  1579. begin
  1580.   if pos(tab,str)=0 then
  1581.     expand := str
  1582.   else
  1583.     begin
  1584.       work := '';
  1585.       for i := 1 to length(str) do
  1586.         if length(work)<240 then
  1587.           if str[i]=tab then
  1588.             for j := 1 to 8-(length(work) and 7) do
  1589.               work := work+' '
  1590.           else
  1591.             work := work+str[i];
  1592.       expand := work;
  1593.     end;
  1594. end;
  1595.  
  1596. function rot13;
  1597.  
  1598. var
  1599.   result: string;
  1600.   upc: char;
  1601.   i: integer;
  1602.  
  1603. begin
  1604.   result := s;
  1605.  
  1606.   for i := 1 to length(result) do
  1607.     begin
  1608.       upc := upcase(result[i]);
  1609.       if (upc>='A') and (upc<='M') then
  1610.         result[i] := chr(ord(result[i])+13)
  1611.       else if (upc>='N') and (upc<='Z') then
  1612.         result[i] := chr(ord(result[i])-13);
  1613.     end;
  1614.  
  1615.   rot13 := result;
  1616. end;
  1617.  
  1618. function indir;
  1619.  
  1620. var
  1621.   fileinfo: searchrec;
  1622.  
  1623. begin
  1624.   findfirst(withbackslash(dir)+filespec,archive,fileinfo);
  1625.   indir := (doserror=0);
  1626. end;
  1627.  
  1628. function default;
  1629.  
  1630. begin
  1631.   if possiblyemptystr='' then
  1632.     default := defaultstr
  1633.   else
  1634.     default := possiblyemptystr;
  1635. end;
  1636.  
  1637. function rpos;
  1638.  
  1639. var
  1640.   result: integer;
  1641.   i: integer;
  1642.  
  1643. begin
  1644.   result := 0;
  1645.  
  1646.   for i := 1 to length(whole)-length(sub)+1 do
  1647.     if copy(whole,i,length(sub))=sub then
  1648.       result := i;
  1649.  
  1650.   rpos := result;
  1651. end;
  1652.  
  1653. function rposc;
  1654.  
  1655. var
  1656.   result: integer;
  1657.   i: integer;
  1658.  
  1659. begin
  1660.   result := 0;
  1661.  
  1662.   for i := 1 to length(s) do
  1663.     if s[i]=c then
  1664.       result := i;
  1665.  
  1666.   rposc := result;
  1667. end;
  1668.  
  1669. function fexists;
  1670.  
  1671. var
  1672.   result: boolean;
  1673.   f: text;
  1674.  
  1675. begin
  1676.   result := false;
  1677.  
  1678.   assign(f,fn);
  1679. {$I-}
  1680.   reset(f);
  1681. {$I+}
  1682.   if ioresult=0 then
  1683.     begin
  1684.       close(f);
  1685.       result := true;
  1686.     end;
  1687.  
  1688.   fexists := result;
  1689. end;
  1690.  
  1691. function dexists;
  1692.  
  1693. var
  1694.   result: boolean;
  1695.   newdn: string;
  1696.   fileinfo: searchrec;
  1697.  
  1698. begin
  1699.   result := false;
  1700.  
  1701.   newdn := unslash(dn);
  1702.   if right(newdn,1)='\' then
  1703.     newdn := newdn+'.';
  1704.   if right(newdn,1)=':' then
  1705.     newdn := newdn+'.';
  1706.  
  1707.   findfirst(newdn,directory,fileinfo);
  1708.  
  1709.   if doserror=0 then
  1710.     if (fileinfo.attr and directory)<>0 then
  1711.       result := true;
  1712.  
  1713.   dexists := result;
  1714. end;
  1715.  
  1716. function getfntime;
  1717.  
  1718. var
  1719.   result: longint;
  1720.   f: text;
  1721.  
  1722. begin
  1723.   result := 0;
  1724.  
  1725.   assign(f,fn);
  1726. {$I-}
  1727.   reset(f);
  1728. {$I+}
  1729.   if ioresult=0 then
  1730.     begin
  1731.       getftime(f,result);
  1732.       close(f);
  1733.     end;
  1734.  
  1735.   getfntime := result;
  1736. end;
  1737.  
  1738. {size from a filename, not from a file handle}
  1739. function getfnsize;
  1740.  
  1741. var
  1742.   result: longint;
  1743.   f: file;
  1744.  
  1745. begin
  1746.   result := -1;
  1747.  
  1748.   assign(f,fn);
  1749. {$I-}
  1750.   reset(f,1);
  1751. {$I+}
  1752.   if ioresult=0 then
  1753.     begin
  1754.       result := filesize(f);
  1755.       close(f);
  1756.     end;
  1757.  
  1758.   getfnsize := result;
  1759. end;
  1760.  
  1761. function withbackslash;  {nonempty gets terminated with backslash}
  1762.  
  1763. var
  1764.   result: string;
  1765.  
  1766. begin
  1767.   result := s;
  1768.   if result<>'' then
  1769.     if result[length(result)]<>'\' then
  1770.       result := result+'\';
  1771.  
  1772.   withbackslash := result;
  1773. end;
  1774.  
  1775. function nobeep;
  1776.  
  1777. var
  1778.   result: string;
  1779.  
  1780. begin
  1781.   result := crepl(s,chr(7),'^');
  1782.   nobeep := result;
  1783. end;
  1784.  
  1785. function nonastychar;
  1786.  
  1787. var
  1788.   result: string;
  1789.  
  1790. begin
  1791.   result := crepl(s,chr(7),'^');
  1792.   result := crepl(result,chr(27),'^');
  1793.   nonastychar := result;
  1794. end;
  1795.  
  1796. function gettag;
  1797.  
  1798. var
  1799.   result: string;
  1800.  
  1801. begin
  1802.   result := '';
  1803.  
  1804.   if pos(tag,s)<>0 then
  1805.     begin
  1806.       result := copy(s,pos(tag,s)+length(tag),255);
  1807.       result := getquoted(result);
  1808.     end;
  1809.  
  1810.   gettag := result;
  1811. end;
  1812.  
  1813. function hexchar;
  1814.  
  1815. begin
  1816.   if i<10 then
  1817.     hexchar := chr(ord('0')+i)
  1818.   else
  1819.     hexchar := chr(ord('a')+i-10);
  1820. end;
  1821.  
  1822. function partialmatch;
  1823.  
  1824. var
  1825.   result: boolean;
  1826.  
  1827. begin
  1828.   result := false;
  1829.  
  1830.   if (length(cmd)<=length(template)) and (length(cmd)>=length(minimum)) then
  1831.     if copy(template,1,length(cmd))=cmd then
  1832.       result := true;
  1833.  
  1834.   partialmatch := result;
  1835. end;
  1836.  
  1837. function doserrorno;  {prevents units having to include dos for 1 call}
  1838.  
  1839. begin
  1840.   doserrorno := doserror;
  1841. end;
  1842.  
  1843. function wordwith;
  1844.  
  1845. var
  1846.   result: string;
  1847.   temps: string;
  1848.  
  1849. begin
  1850.   result := '';
  1851.   temps := s;
  1852.  
  1853.   while (result='') and (temps<>'') do
  1854.     begin
  1855.       result := chopfirstw(temps);
  1856.       if pos(c,result)=0 then
  1857.         result := '';
  1858.     end;
  1859.  
  1860.   wordwith := result;
  1861. end;
  1862.  
  1863. function isasciifile;
  1864.  
  1865. const
  1866.   checkedsize=1024;
  1867.  
  1868. var
  1869.   result: boolean;
  1870.  
  1871. {$ifdef veryslowisasciifile}
  1872.   inf: file of byte;
  1873. {$endif}
  1874.   inf: file;
  1875.   whichbyte: integer;
  1876.   onebyte: byte;
  1877. {$ifdef veryslowisasciifile}
  1878.   stillsearching: boolean;
  1879. {$endif}
  1880.   buffer: array[1..checkedsize] of byte;
  1881.   numread: word;
  1882.  
  1883. begin
  1884.   result := true;
  1885.  
  1886. {$ifdef veryslowisasciifile}
  1887.   assign(inf,fn);
  1888. {$I-}
  1889.   reset(inf);
  1890. {$I+}
  1891. {$endif}
  1892.  
  1893.   assign(inf,fn);
  1894. {$I-}
  1895.   reset(inf,1);
  1896. {$I+}
  1897.  
  1898.   if ioresult<>0 then
  1899.     result := false
  1900.   else
  1901.     begin
  1902. {$ifdef veryslowisasciifile}
  1903.       stillsearching := true;
  1904.  
  1905.       for whichbyte := 1 to checkedsize do
  1906.         if stillsearching then
  1907.           begin
  1908.             if eof(inf) then
  1909.               stillsearching := false
  1910.             else
  1911.               begin
  1912.                 read(inf,onebyte);
  1913.                 if not
  1914.                 (
  1915.                  (onebyte=9)
  1916.                 or
  1917.                  (onebyte=10)
  1918.                 or
  1919.                  (onebyte=13)
  1920.                 or
  1921.                  ( (onebyte>=32) and (onebyte<=126) )
  1922.                 )
  1923.                   then
  1924.                     begin
  1925.                       result := false;
  1926.                       stillsearching := false;
  1927.                     end;
  1928.               end;
  1929.           end;
  1930.       close(inf);
  1931. {$endif}
  1932.  
  1933.       blockread(inf,buffer,checkedsize,numread);
  1934.       close(inf);
  1935.  
  1936.       for whichbyte := 1 to numread do
  1937.         if result then
  1938.           begin
  1939.             onebyte := buffer[whichbyte];
  1940.             if not
  1941.             (
  1942.              (onebyte=9)
  1943.             or
  1944.              (onebyte=10)
  1945.             or
  1946.              (onebyte=13)
  1947.             or
  1948.              ( (onebyte>=32) and (onebyte<=126) )
  1949.             )
  1950.               then
  1951.                 result := false;
  1952.           end;
  1953.  
  1954.     end;
  1955.  
  1956.   isasciifile := result;
  1957. end;
  1958.  
  1959. function nthfield;
  1960.  
  1961. var
  1962.   result: string;
  1963.   chopfieldcount: integer;
  1964.   delimpos: integer;
  1965.   tempstring: string;
  1966.  
  1967. begin
  1968.   tempstring := astring;
  1969.   for chopfieldcount := 1 to n-1 do
  1970.     tempstring := lchop(tempstring,pos(delim,tempstring));
  1971.  
  1972.   delimpos := pos(delim,tempstring);
  1973.   if delimpos=0 then
  1974.     result := ''
  1975.   else
  1976.     result := copy(tempstring,1,delimpos-1);
  1977.  
  1978.   nthfield := result;
  1979. end;
  1980.  
  1981. function isinlist;
  1982.  
  1983. begin
  1984.   isinlist := pos(delim+upper(astring)+delim,delim+upper(alist)+delim)<>0;
  1985. end;
  1986.  
  1987. function sornos;
  1988.  
  1989. begin
  1990.   if n=1 then sornos := '' else sornos := 's';
  1991. end;
  1992.  
  1993. {}{}{}{} { this is NOT full regex at this time }
  1994.  
  1995. function regexintext;
  1996.  
  1997. var
  1998.   result: boolean;
  1999.   mangledaregex: string;
  2000.   onesearch: string;
  2001.   foundend: boolean;
  2002.   escaped: boolean;
  2003.   onech: char;
  2004.  
  2005. begin
  2006.   result := false;
  2007.  
  2008.   if pos('|',aregex)=0 then
  2009.     result := pos(aregex,awholetext)<>0
  2010.   else
  2011.     begin
  2012.       mangledaregex := aregex;
  2013.       while (mangledaregex<>'') and not result do
  2014.         begin
  2015.           onesearch := '';
  2016.           escaped := false;
  2017.  
  2018.           foundend := false;
  2019.           while not foundend do
  2020.             begin
  2021.               if mangledaregex='' then
  2022.                 foundend := true
  2023.               else
  2024.                 begin
  2025.                   onech := mangledaregex[1];
  2026.                   mangledaregex := lchop(mangledaregex,1);
  2027.                   if escaped then
  2028.                     begin
  2029.                       escaped := false;
  2030.                       onesearch := onesearch+onech;
  2031.                     end
  2032.                   else if onech='\' then
  2033.                     begin
  2034.                       escaped := true;
  2035.                     end
  2036.                   else
  2037.                     begin
  2038.                       escaped := false;
  2039.                       if onech='|' then
  2040.                         foundend := true
  2041.                       else
  2042.                         onesearch := onesearch+onech;
  2043.                     end;
  2044.                 end;
  2045.             end;
  2046.  
  2047.           result := pos(onesearch,awholetext)<>0;
  2048.  
  2049.         end;
  2050.     end;
  2051.  
  2052.   regexintext := result;
  2053. end;
  2054.  
  2055. function enclosedin;
  2056.  
  2057. begin
  2058.   if length(astring)<2 then
  2059.     enclosedin := false
  2060.   else
  2061.     enclosedin := (astring[1]=lchar) and (astring[length(astring)]=rchar);
  2062. end;
  2063.  
  2064. function isaleapyear;
  2065.  
  2066. begin
  2067.   if (ayear mod 400)=0 then
  2068.     isaleapyear := true
  2069.   else if (ayear mod 100)=0 then
  2070.     isaleapyear := false
  2071.   else if (ayear mod 4)=0 then
  2072.     isaleapyear := true
  2073.   else
  2074.     isaleapyear := false;
  2075. end;
  2076.  
  2077. function daysinyear;
  2078.  
  2079. begin
  2080.   if isaleapyear(ayear) then
  2081.     daysinyear := 366
  2082.   else
  2083.     daysinyear := 365;
  2084. end;
  2085.  
  2086. function daysinyearmonth;
  2087.  
  2088. begin
  2089.   case amonth of
  2090.      1: daysinyearmonth := 31;
  2091.      2: if isaleapyear(ayear) then
  2092.           daysinyearmonth := 29
  2093.         else
  2094.           daysinyearmonth := 28;
  2095.      3: daysinyearmonth := 31;
  2096.      4: daysinyearmonth := 30;
  2097.      5: daysinyearmonth := 31;
  2098.      6: daysinyearmonth := 30;
  2099.      7: daysinyearmonth := 31;
  2100.      8: daysinyearmonth := 31;
  2101.      9: daysinyearmonth := 30;
  2102.     10: daysinyearmonth := 31;
  2103.     11: daysinyearmonth := 30;
  2104.     12: daysinyearmonth := 31;
  2105.   end;
  2106. end;
  2107.  
  2108. function dayspast1970;
  2109.  
  2110. var
  2111.   result: longint;
  2112.   ayear: integer;
  2113.   amonth: integer;
  2114.  
  2115. begin
  2116.   result := 0;
  2117.  
  2118.   if y>=1970 then
  2119.     begin
  2120.       for ayear := 1970 to y-1 do
  2121.         inc(result,daysinyear(ayear));
  2122.  
  2123.       for amonth := 1 to m-1 do
  2124.         inc(result,daysinyearmonth(ayear,amonth));
  2125.  
  2126.       inc(result,d-1);
  2127.     end;
  2128.  
  2129.   dayspast1970 := result;
  2130. end;
  2131.  
  2132.  
  2133.  
  2134.  
  2135.  
  2136. {weird code follows}
  2137.  
  2138. {$ifdef VER40}
  2139. function dosversion;
  2140.  
  2141. var
  2142.   regs: registers;
  2143.  
  2144. begin
  2145.   regs.ah := $30;
  2146.   msdos(regs);
  2147.   dosversion := regs.ax;
  2148. end;
  2149. {$endif}
  2150.  
  2151. {$ifdef floatingpoint}
  2152. function ator;
  2153.  
  2154. var
  2155.   r: real;
  2156.   code: word;
  2157.  
  2158. begin
  2159.   val(s,r,code);
  2160.   ator := r;
  2161. end;
  2162.  
  2163. function rtoa;
  2164.  
  2165. var
  2166.   a: string;
  2167.  
  2168. begin
  2169.   str(r,a);
  2170.   rtoa := a;
  2171. end;
  2172.  
  2173. function rwptoa;
  2174.  
  2175. var
  2176.   a: string;
  2177.  
  2178. begin
  2179.   str(r:width:precision,a);
  2180.   rwptoa := a;
  2181. end;
  2182.  
  2183. function rtonicea;
  2184.  
  2185. var
  2186.   a: string;
  2187.  
  2188. begin
  2189.   str(r:0:10,a);
  2190.   while (length(a)>1) and (right(a,1)='0') do
  2191.     a := copy(a,1,length(a)-1);
  2192.   if right(a,1)='.' then
  2193.     a := copy(a,1,length(a)-1);
  2194.   rtonicea := a;
  2195. end;
  2196.  
  2197. {$endif}
  2198.  
  2199. end.
  2200.